home *** CD-ROM | disk | FTP | other *** search
/ NeXT Education Software Sampler 1992 Fall / NeXT Education Software Sampler 1992 Fall.iso / Programming / Source / nxyplot1.87 / auxil.m next >
Encoding:
Text File  |  1991-12-03  |  6.9 KB  |  294 lines

  1. /*
  2.  * Auxiliary routines, all taken from xyplot (translated from Fortran to C).
  3.  */
  4.  
  5. #include "defs.h"
  6. #include <strings.h>
  7. #include <stdio.h>
  8. #include <math.h>
  9. #include <stdlib.h>        /* for exit() */
  10. #include <appkit/Panel.h>    /* for NXRunAlertPanel */
  11.  
  12. /*
  13.  * Count the number of labels on a given axis.
  14.  */
  15. void
  16. count_labels(int *pn, double *pfirst, double min, double inc, double max)
  17. {
  18.   int   bottom, top, j;
  19.   double range, absinc, tol, guess;
  20.   
  21.   if (inc != 0.0) {
  22.     *pn  = 0;
  23.     bottom = (int)(min/inc) - 1;
  24.     top    = (int)(max/inc) + 1;
  25.     range  = ABS(max - min);
  26.     absinc = MIN(range, ABS(inc));
  27.     tol    = absinc * (range + absinc) / 100.0;
  28.     for (j=top; j>=bottom; j--) {
  29.       guess = (double)j * inc;
  30.       if ( (max-guess)*(guess-min) >= -tol) {
  31.     *pn += 1;
  32.     *pfirst = guess;
  33.       }
  34.     }
  35.   }
  36.   else {
  37.     *pn     = 0;
  38.     *pfirst = 0.0;
  39.   }
  40.   return;
  41. }
  42.  
  43. /*
  44.  * Write a float into a string and see how many characters are to the left
  45.  * of the decimal point, how many total decimal characters there are, and
  46.  * how many characters there are in the exponent (if exponential notation).
  47.  */
  48. void
  49. numstring(double x, int *nl, int *nd, int *ne)
  50. {
  51.   char string[80];
  52.   double  ax;
  53.   int     i, nc, net;
  54.  
  55.   ax = ABS(x);
  56.   i  = ax;
  57.   if ((double)i==ax  &&  ax<99999.0) {
  58.     sprintf(string, "%1d", (int)x);
  59.   }
  60.   else {
  61.     if (ax>=1.e-4  && ax<1.e5) {
  62.       if ( ((int)(x*10000.0) % 10000) == 0 )
  63.     sprintf(string, "%-6.0f", x); /* left-justify  */
  64.       else if ( ((int)(x*10000.0) % 1000) == 0 )
  65.     sprintf(string, "%-7.1f", x);
  66.       else if ( ((int)(x*10000.0) % 100) == 0 )
  67.     sprintf(string, "%-8.2f", x);
  68.       else if ( ((int)(x*10000.0) % 10) == 0 )
  69.     sprintf(string, "%-9.3f", x);
  70.       else
  71. /*    sprintf(string, "%-10.4f", x);  this can fail -- e.g., x=0.000718 */
  72.     sprintf(string, "%10.6f", x); /* will this always work? */
  73.     }
  74.     else {
  75.       sprintf(string, "%-#11.2e", x);
  76.     }
  77.   }
  78.   nc = strlen(string);
  79. /* strip off blanks from the end of the string: */
  80.   while (string[nc-1] == ' ') {
  81.     string[--nc] = '\0';
  82.   }
  83.   nc = strlen(string);
  84.  
  85. /* nl = no. of characters left of the decimal point (including sign) */
  86.   *nl = 0;
  87.   for (i=nc-1; i>=0; i--) {
  88.     *nl += 1;
  89.     if (string[i] == '.') *nl = 0;
  90.   }
  91.  
  92. /* nd = no. of decimal characters (including decimal point, omitting
  93.  * trailing zeros)
  94.  */
  95.   *nd = 0;
  96.   for (i=nc-1; i>=*nl; i--) {
  97.     *nd += 1;
  98.     if (string[i] == 'e' || string[i] == 'E') *nd = 0;
  99.     if (string[i] == '0' && *nd == 1) *nd = 0;
  100.   }
  101.  
  102. /* ne = no. of exponent characters (including the 'E' if any) */
  103.   *ne = 0;
  104.   for (i=*nl + *nd; i<nc; i++) {
  105.     if (string[i] == 'e' || string[i] == 'E') *ne = nc - i;
  106.   }
  107.   net = 0;
  108.   for (i = nc-1; i >= nc - *ne + 2; i--) {
  109.     if (string[i] != '0') net = 2 + nc - i;
  110.   }
  111.   *ne = net;
  112.  
  113. /* Some special cases where floating point numbers may be
  114.  * expressed as integers.
  115.  */
  116.   if (*nd==1 && *ne==0) *nd = 1;
  117.   return;
  118. }
  119.  
  120. /*
  121.  * See what the formatting would be if we go from min to max in
  122.  * steps of inc.
  123.  */
  124. void
  125. autoformat(double min, double inc, double max, int *axformat)
  126. {
  127.   int     nlabels, i, nl, nd, ne;
  128.   double  first, value;
  129.  
  130.   *axformat       = 0;
  131.   *(axformat + 1) = 0;
  132.   *(axformat + 2) = 0;
  133.   count_labels(&nlabels, &first, min, inc, max);
  134.   for (i=0; i<nlabels; i++) {
  135.     /* Special test here for what should be exact 0 (but isn't sometimes
  136.      * due to floating-point arithmetic.
  137.      */
  138.     if (inc != 0.0  && fabs(first/inc + (double)i) < 1.0e-14) {    /* ugly */
  139.       value = 0.0;
  140.     }
  141.     else {
  142.       value = first + inc*(double)i;
  143.     }
  144.     numstring(value, &nl, &nd, &ne);
  145.     if (*(axformat+2)==0 && ne!=0) {
  146.       *axformat     = nl;
  147.       *(axformat+1) = nd;
  148.       *(axformat+2) = ne;
  149.     }
  150.     else {
  151.       *axformat     = MAX(nl, *axformat);
  152.       *(axformat+1) = MAX(nd, *(axformat+1));
  153.       *(axformat+2) = MAX(ne, *(axformat+2));
  154.     }
  155.   }
  156.   return;
  157. }
  158.  
  159. /*
  160.  * Put a float into a string with a specified format.
  161.  */
  162. void
  163. handformat(float number, char *string, int *axformat)
  164. {
  165.   int  nl, nd, ne;
  166.  
  167.   nl = *(axformat+0);
  168.   nd = *(axformat+1);
  169.   ne = *(axformat+2);
  170.  
  171.   // if all axformat[i] are 0, return just a blank:
  172.   if (ne==0 && nd==0 && nl==0) {
  173.     sprintf(string, " ");
  174.     return;
  175.   }
  176.  
  177.   // special case 0:
  178.   if (number == 0.0) {
  179.     sprintf(string, "%1d", 0);
  180.     return;
  181.   }
  182.   if (ne==0) {
  183.     if (nd==0) {
  184.       sprintf(string, "%*d", nl, (int)rint((double)number));
  185.     }
  186.     else
  187.       sprintf(string, "%*.*f", nl, nd-1, number);
  188.   }
  189.   else {
  190.     if (nd==0)
  191.       sprintf(string, "%*.*e", nl, nd, number);
  192.     else
  193.       sprintf(string, "%*.*e", ne+1, nd-1, number);
  194.   }
  195.   return;
  196. }
  197.  
  198. /*
  199.  * Compute nice increment for linear plotting, given min and max.
  200.  */
  201. void
  202. computeNiceLinInc(float *pmin, float *pmax, float *pinc)
  203. {
  204.   float fmin = *pmin, fmax = *pmax, finc = (fmax - fmin)/5.0, x;
  205.   int n;
  206.  
  207.   if (finc <= 0.0) {
  208.     fmin = (fmin>0.0? 0.9*fmin : 1.1*fmin);
  209.     fmax = (fmax>0.0? 1.1*fmax : 0.9*fmax);
  210.     finc = (fmax - fmin)/5.0;
  211.     // for safety:
  212.     if (finc < 0.0) {
  213.       n = NXRunAlertPanel("computeNiceLinInc",
  214.               "Impossible increment = %g.\n"
  215.               "I'm very confused "
  216.               "(Perhaps all data is being ignored -- no lines, no symbols)",
  217.               "Quit", "Continue", NULL, finc);
  218.       if (n==NX_ALERTDEFAULT)
  219.     exit(0);
  220.       else if (n==NX_ALERTALTERNATE) {
  221.     *pmin = 0.0;
  222.     *pmax = 1.0;
  223.     *pinc = 0.2;
  224.     return;
  225.       }
  226.     }
  227.   }
  228.   n = ( log10((double)finc) >= 0.0 ? (int)floor(log10((double)finc)) :
  229.        (int)ceil(log10((double)finc)) );
  230.   if (finc > 1.0) n++;
  231.   x = finc * (float)pow((double)10.0, (double)(-n));
  232.   finc = 0.1;
  233.   if (x > 0.1)  finc = 0.2;
  234.   if (x > 0.2)  finc = 0.25;
  235.   if (x > 0.25) finc = 0.5;
  236.   if (x > 0.5)  finc = 1.0;
  237.   finc = finc * (float)pow((double)10.0, (double)n);
  238.  
  239.   if (fmin < ((int)(fmin/finc))*finc) fmin = ((int)(fmin/finc - 1))*finc;
  240.   else                                fmin = ((int)(fmin/finc))*finc;
  241.  
  242.   if (fmax > ((int)(fmax/finc))*finc) fmax = ((int)(fmax/finc + 1))*finc;
  243.   else                                fmax = ((int)(fmax/finc))*finc;
  244.  
  245.   *pmin = fmin;
  246.   *pmax = fmax;
  247.   *pinc = finc;
  248.   return;
  249. }
  250.  
  251.  
  252. /*
  253.  * Compute a nice min and max for logarithmic plotting (we take increment=1).
  254.  */
  255. void
  256. computeNiceLogInc(float *pmin, float *pmax, float *pinc)
  257. {
  258.   float fmin, fmax, finc;
  259.   int n;
  260.  
  261.   // for safety:
  262.   if (*pmin <= 0.0 || *pmax <= 0.0) {
  263.       n = NXRunAlertPanel("computeNiceLogInc",
  264.               "Impossible min/max = %g, %g.\n"
  265.               "I'm very confused "
  266.               "(Perhaps all data is being ignored -- no lines, no symbols)",
  267.               "Quit", "Continue", NULL, *pmin, *pmax);
  268.       if (n==NX_ALERTDEFAULT)
  269.     exit(0);
  270.       else if (n==NX_ALERTALTERNATE) {
  271.     *pmin = 1.0;
  272.     *pmax = 10.0;
  273.     *pinc = 1.0;
  274.     return;
  275.       }
  276.     }
  277.  
  278.   fmin = (float)log10(*pmin);
  279.   fmax = (float)log10(*pmax);
  280.   finc = 1.0;
  281.  
  282.   fmin = (float) floor((double)fmin);
  283.   fmax = (float) ceil((double)fmax);
  284.  
  285.   if (fmin == fmax) {
  286.     fmin = fmin - 1.0;
  287.     fmax = fmax + 1.0;
  288.   }
  289.   *pmin = (float)pow((double)10.0, (double)fmin);
  290.   *pmax = (float)pow((double)10.0, (double)fmax);
  291.   *pinc = (float)pow((double)10.0, (double)finc);
  292.   return;
  293. }
  294.